package com.wildwolf.project.wildwolf.ui;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;

import org.jivesoftware.smack.util.StringUtils;

import android.app.Dialog;
import android.content.ComponentName;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.preference.PreferenceManager;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewStub;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.BaseAdapter;
import android.widget.Gallery;
import android.widget.LinearLayout;

import com.wildwolf.project.wildwolf.WildWolfApplication;
import com.wildwolf.project.wildwolf.adapter.ContactListAdapter;
import com.wildwolf.project.wildwolf.service.Contact;
import com.wildwolf.project.wildwolf.service.PresenceAdapter;
import com.wildwolf.project.wildwolf.service.aidl.IWildwolfRosterListener;
import com.wildwolf.project.wildwolf.service.aidl.IChatManager;
import com.wildwolf.project.wildwolf.service.aidl.IRoster;
import com.wildwolf.project.wildwolf.service.aidl.IXmppFacade;
import com.wildwolf.project.wildwolf.ui.dialogs.builders.Alias;
import com.wildwolf.project.wildwolf.ui.dialogs.builders.ChatList;
import com.wildwolf.project.wildwolf.ui.dialogs.builders.DeleteContact;
import com.wildwolf.project.wildwolf.ui.dialogs.builders.ResendSubscription;
import com.wildwolf.project.wildwolf.ui.views.SectionTextView;
import com.wildwolf.project.wildwolf.utils.LogTagUtil;
import com.wildwolf.project.wildwolf.utils.WildWolfBroadcastReceiver;
import com.wildwolf.project.wildwolf.R;

/**
 * 显示用户列表
 * 
 * @author LEON
 * 
 */
public class ContactListActivity extends FragmentActivity {
	/**
	 * 服务对象
	 */
	private static final Intent SERVICE_INTENT = new Intent();
	static {
		SERVICE_INTENT.setComponent(new ComponentName(
				"com.wildwolf.project.wildwolf",
				"com.wildwolf.project.wildwolf.WildWolfService"));
	}

	private static final String TAG = LogTagUtil
			.getLogTag(ContactListActivity.class);

	private final List<GroupHolder> mListGroup = new ArrayList<GroupHolder>();

	/**
	 * Map containing a list of the different contacts of a given group. Each
	 * list is a @{link SortedList} so there is no need to sort it again.
	 * */
	private final Map<String, List<Contact>> mContactOnGroup = new HashMap<String, List<Contact>>();

	private final ServiceConnection mServConn = new WildwolfServiceConnection();
	/**
	 * 广播
	 */
	private final WildWolfBroadcastReceiver mReceiver = new WildWolfBroadcastReceiver();
	
	private final WildwolfBanner mAdapterBanner = new WildwolfBanner();
	
	private final Map<String, ContactListAdapter> contactListAdapters = new HashMap<String, ContactListAdapter>();
	/**
	 * 好友监听器
	 */
	private final WildwolfRosterListener wildwolfRosterListener = new WildwolfRosterListener();
	private IRoster mRoster;
	private IXmppFacade mXmppFacade;
	private IChatManager mChatManager;
	private SharedPreferences mSettings;
	private LayoutInflater mInflater;
	private boolean mBinded;
	private ViewPager viewPager;
	private ListPagerAdapter groupsPagesAdapter;
	private Gallery groupGallery;

	/**
	 * Constructor.
	 */
	public ContactListActivity() {
	}

	/**
	 * Callback for menu creation.
	 * 
	 * @param menu
	 *            the menu created
	 * @return true on success, false otherwise
	 */
	@Override
	public final boolean onCreateOptionsMenu(Menu menu) {
		super.onCreateOptionsMenu(menu);
		MenuInflater inflater = getMenuInflater();
		inflater.inflate(R.menu.contact_list, menu);
		return true;
	}

	@Override
	public final boolean onOptionsItemSelected(MenuItem item) {
		switch (item.getItemId()) {
		case R.id.contact_list_menu_settings:
			// startActivity(new Intent(this, Settings.class));
			return true;
		case R.id.contact_list_menu_add_contact:
			startActivity(new Intent(ContactListActivity.this,
					AddContactActivity.class));
			return true;
		case R.id.menu_change_status:
			startActivity(new Intent(ContactListActivity.this,
					ChangeStatus.class));
			return true;
			/*
			  case R.id.contact_list_menu_chatlist: List<Contact> openedChats;
			 try { openedChats = mChatManager.getOpenedChatList(); Log.d(TAG,
			  "opened chats = " + openedChats); Dialog chatList = new
			  ChatList(ContactListActivity.this, openedChats).create();
			  chatList.show(); } catch (RemoteException e) {
			  e.printStackTrace(); } return true;
			 */
		case R.id.menu_disconnect:
			stopService(SERVICE_INTENT);
			finish();
			return true;
		default:
			return false;
		}
	}

	@Override
	protected void onCreate(Bundle saveBundle) {
		super.onCreate(saveBundle);
		mSettings = PreferenceManager.getDefaultSharedPreferences(this);
		setContentView(R.layout.contactlist);

		this.registerReceiver(mReceiver, new IntentFilter(WildWolfBroadcastReceiver.WILDWOLF_CONNECTION_CLOSED));

		mInflater = getLayoutInflater();

		viewPager = (ViewPager) findViewById(R.id.pager);
		viewPager.setOnPageChangeListener(new OnPageChangeListener());
		groupsPagesAdapter = new ListPagerAdapter(getSupportFragmentManager(),
				viewPager);

		mListGroup.add(new GroupHolder(
				getString(R.string.contact_list_all_contact)));
		mListGroup.add(new GroupHolder(
				getString(R.string.contact_list_no_group)));
		mAdapterBanner.notifyDataSetChanged();
	}

	@Override
	protected void onStart() {
		super.onStart();
		if (!mSettings.getBoolean(WildWolfApplication.HIDE_GROUPS_KEY, false))
			showGroups();
		else
			hideGroups();

		if (!mBinded)
			mBinded = bindService(SERVICE_INTENT, mServConn, BIND_AUTO_CREATE);
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	protected void onPause() {
		super.onPause();
		try {
			if (mRoster != null) {
				mRoster.removeRosterListener(wildwolfRosterListener);
				mRoster = null;
			}
		} catch (RemoteException e) {
			Log.d("ContactList", "Remote exception", e);
		}
		if (mBinded) {
			unbindService(mServConn);
			mBinded = false;
		}
		mXmppFacade = null;
	}

	@Override
	protected void onDestroy() {
		super.onDestroy();
		this.unregisterReceiver(mReceiver);
		Log.e(TAG, "onDestroy activity");
	}

	/**
	 * Get a {@link ContactListAdapter} for a group. The
	 * {@link ContactListAdapter} will be created if it is not exist.
	 * 
	 * @param group
	 *            the group
	 * @return the adapter
	 */
	ContactListAdapter getContactListAdapter(String group) {
		synchronized (contactListAdapters) {
			ContactListAdapter contactListAdapter = contactListAdapters
					.get(group);
			if (contactListAdapter == null) {
				contactListAdapter = new ContactListAdapter(
						ContactListActivity.this);
				contactListAdapters.put(group, contactListAdapter);
				List<GroupHolder> realGroups = mListGroup.subList(1,
						mListGroup.size() - 1);
				if (!GroupHolder.contains(mListGroup, group)) {
					GroupHolder gh = new GroupHolder(group);
					boolean added = false;
					// insert group in sorted list
					for (ListIterator<GroupHolder> iterator = realGroups
							.listIterator(); iterator.hasNext();) {
						GroupHolder currentGroup = (GroupHolder) iterator
								.next();
						if (currentGroup.groupName.compareTo(group) > 0) {
							iterator.previous();
							iterator.add(gh);
							added = true;
							break;
						}
					}
					if (!added)
						realGroups.add(gh);
					groupsPagesAdapter.notifyDataSetChanged();
					mAdapterBanner.notifyDataSetChanged();
				}
			}
			boolean hideDisconnected = mSettings.getBoolean(
					WildWolfApplication.SHOW_OFFLINE_CONTACTS_KEY, false);
			contactListAdapter.setOnlineOnly(hideDisconnected);
			return contactListAdapter;
		}
	}

	/**
	 * Exectute a context menu action on a specified contact.
	 * 
	 * @param itemId
	 *            the id of the menu action
	 * @param contact
	 *            the contact
	 */
	void doContextMenuAction(int itemId, Contact contact) {
		switch (itemId) {
		case R.id.contact_list_context_menu_call_item:
			try {
				mXmppFacade.call(contact.getJID() + "/psi");
			} catch (RemoteException e) {
				e.printStackTrace();
			}
			break;
		case R.id.contact_list_context_menu_userinfo_alias:
			Dialog alias = new Alias(ContactListActivity.this, mRoster, contact).create();
			alias.show();
			break;
		case R.id.contact_list_context_menu_userinfo_subscription:
			Dialog subscription = new ResendSubscription(
					ContactListActivity.this, mXmppFacade, contact).create();
			subscription.show();
			break;
		case R.id.contact_list_context_menu_userinfo_delete:
			Dialog delete = new DeleteContact(ContactListActivity.this,
					mRoster, contact).create();
			delete.show();
			break;
		default:
			Log.w(TAG, "Context menu action not supported" + itemId);
			break;
		}

	}

	/**
	 * Show the groups view.
	 */
	private void showGroups() {

		ViewStub stub = (ViewStub) findViewById(R.id.contactlist_stub);
		if (stub != null) {
			View v = stub.inflate();
			groupGallery = (Gallery) v.findViewById(R.id.contactlist_banner);
			groupGallery.setOnItemClickListener(new OnItemClickGroupName());
			groupGallery.setAdapter(mAdapterBanner);
			groupGallery.setSelection(0);
		} else {
			((LinearLayout) findViewById(R.id.contactlist_groupstub))
					.setVisibility(View.VISIBLE);
			groupGallery = (Gallery) findViewById(R.id.contactlist_banner);
			groupGallery.setSelection(0);
		}
		GroupHolder.setUniquePrincipal(mListGroup, 0);
	}

	/**
	 * Hide the groups view.
	 */
	private void hideGroups() {
		View v = findViewById(R.id.contactlist_groupstub);
		if (v != null)
			v.setVisibility(View.GONE);
	}

	/**
	 * Remove old groups on the banner.
	 * 
	 * @throws RemoteException
	 *             if an error occur when communicating with the service
	 */
	private void cleanBannerGroup() throws RemoteException {
		if (mListGroup.size() <= 2)
			return;
		List<String> rosterGroups = mRoster.getGroupsNames();
		Collections.sort(rosterGroups);
		List<GroupHolder> realGroups = mListGroup.subList(1,
				mListGroup.size() - 1);
		realGroups.clear();
		realGroups.addAll(GroupHolder.establishGroupHolder(rosterGroups));
		// restore principal
		GroupHolder.setUniquePrincipal(mListGroup, viewPager.getCurrentItem());
		mAdapterBanner.notifyDataSetChanged();
		groupsPagesAdapter.notifyDataSetChanged();
	}

	/**
	 * 添加联系人到默认组中 “所有联系人” 没有组 The contact will be added if the list is not the
	 * current list otherwise the list must be modified in a Handler.
	 * 
	 * @param contact
	 *            the contact to add.
	 */
	private void addToSpecialList(Contact contact) {
		List<String> groups = contact.getGroups();

		ContactListAdapter adapter = getContactListAdapter(getString(R.string.contact_list_all_contact));
		adapter.put(contact);
		/*
		 * if (groups.isEmpty()) { adapter =
		 * getContactListAdapter(getString(R.string.contact_list_no_group));
		 * adapter.put(contact); }
		 */
	}

	/**
	 * Listener on service event.
	 */
	private class WildwolfRosterListener extends IWildwolfRosterListener.Stub {
		/**
		 * Constructor.
		 */
		public WildwolfRosterListener() {
		}

		/**
		 * {@inheritDoc} Simple stategy to handle the onEntriesAdded event. if
		 * contact has to be shown :
		 * <ul>
		 * <li>add him to his groups</li>
		 * <li>add him to the specials groups</>
		 * </ul>
		 */
		@Override
		public void onEntriesAdded(final List<String> addresses)
				throws RemoteException {
			for (String newName : addresses) {
				final Contact contact = mRoster.getContact(StringUtils
						.parseBareAddress(newName));
				putContactInList(contact);
			}
		}

		/**
		 * {@inheritDoc} Simple stategy to handle the onEntriesDeleted event.
		 * <ul>
		 * <li>Remove the contact from all groups</li>
		 * </ul>
		 */
		@Override
		public void onEntriesDeleted(final List<String> addresses)
				throws RemoteException {
			Log.d(TAG, "onEntries deleted " + addresses);
			for (String cToDelete : addresses) {
				final Contact contact = new Contact(cToDelete);
				for (final ContactListAdapter adapter : contactListAdapters
						.values()) {
					runOnUiThread(new Runnable() {

						@Override
						public void run() {
							adapter.remove(contact);
						}
					});
				}
			}
			cleanBannerGroup();

		}

		/**
		 * {@inheritDoc} Simple stategy to handle the onEntriesUpdated event.
		 * <ul>
		 * <li>Remove the contact from all groups</li>
		 * <li>if contact has to be shown add it to his groups</li>
		 * <li>if contact has to be shown add it to the specials groups</li>
		 * </ul>
		 */
		@Override
		public void onEntriesUpdated(final List<String> addresses)
				throws RemoteException {
			Log.d(TAG, "onEntries updated " + addresses);
			for (String cToDelete : addresses) {
				Contact contact = new Contact(cToDelete);
				for (ContactListAdapter adapter : contactListAdapters.values()) {
					adapter.remove(contact);
				}
			}
			for (String newName : addresses) {
				final Contact contact = mRoster.getContact(StringUtils
						.parseBareAddress(newName));
				putContactInList(contact);
			}
			cleanBannerGroup();
		}

		/**
		 * {@inheritDoc} Simple stategy to handle the onPresenceChanged event.
		 * <ul>
		 * <li>Remove the contact from all groups</li>
		 * <li>if contact has to be shown add it to his groups</li>
		 * <li>if contact has to be shown add it to the specials groups</li>
		 * </ul>
		 */
		@Override
		public void onPresenceChanged(PresenceAdapter presence)
				throws RemoteException {
			String from = presence.getFrom();
			final Contact contact = mRoster.getContact(StringUtils
					.parseBareAddress(from));
			putContactInList(contact);
		}

		/**
		 * Put a contact in the different group list.
		 * 
		 * @param contact
		 *            the contact
		 */
		private void putContactInList(final Contact contact) {
			List<String> groups = contact.getGroups();
			for (final String group : groups) {
				runOnUiThread(new Runnable() {

					@Override
					public void run() {
						ContactListAdapter contactListAdapter = getContactListAdapter(group);
						contactListAdapter.put(contact);
					}
				});
			}

			runOnUiThread(new Runnable() {

				@Override
				public void run() {
					addToSpecialList(contact);
				}
			});
		}
	}

	/**
	 * Adapter banner list.
	 */
	private class WildwolfBanner extends BaseAdapter {

		/**
		 * Constructor.
		 */
		public WildwolfBanner() {
		}

		@Override
		public int getCount() {
			return mListGroup.size();
		}

		@Override
		public Object getItem(int position) {
			return mListGroup.get(position);
		}

		@Override
		public long getItemId(int position) {
			return position;
		}

		@Override
		public View getView(int position, View convertView, ViewGroup parent) {
			SectionTextView v = (SectionTextView) convertView;
			if (convertView == null) {
				v = (SectionTextView) mInflater.inflate(
						R.layout.contactlist_group, null);
			}
			GroupHolder gh = (GroupHolder) getItem(position);
			v.setText(gh.groupName);
			v.setPrincipal(gh.isPrincipal);
			return v;
		}
	}

	/**
	 * XMpp 服务
	 */
	private class WildwolfServiceConnection implements ServiceConnection {

		/**
		 * Constructor.
		 */
		public WildwolfServiceConnection() {
		}

		@Override
		public void onServiceConnected(ComponentName name, IBinder service) {
			mXmppFacade = IXmppFacade.Stub.asInterface(service);
			try {
				mRoster = mXmppFacade.getRoster();
				if (mRoster != null) {
					List<String> tmpGroupList = mRoster.getGroupsNames();
					cleanBannerGroup();
					synchronized (contactListAdapters) {
						for (ContactListAdapter ca : contactListAdapters
								.values()) {
							ca.clear();
						}
					}
					assignContactToGroups(mRoster.getContactList(),
							tmpGroupList);

					mRoster.addRosterListener(wildwolfRosterListener);
					Log.d(TAG, "add roster listener");
					mChatManager = mXmppFacade.getChatManager();
				}
			} catch (RemoteException e) {
				e.printStackTrace();
			}
		}

		@Override
		public void onServiceDisconnected(ComponentName name) {
			try {
				mRoster.removeRosterListener(wildwolfRosterListener);
			} catch (RemoteException e) {
				e.printStackTrace();
			}
			mXmppFacade = null;
			mChatManager = null;
			mRoster = null;
			mListGroup.clear();
			mContactOnGroup.clear();
			mBinded = false;

		}

		/**
		 * 分组将联系人分组 This methods will fill the mContactOnGroup map.
		 * 
		 * @param contacts
		 *            显示的联系人
		 * @param groupNames
		 *            list of existing groups
		 */
		private void assignContactToGroups(List<Contact> contacts,
				List<String> groupNames) {
			for (Contact c : contacts) {
				addToSpecialList(c);

				List<String> groups = c.getGroups();

				for (String currentGroup : groups) {
					ContactListAdapter cl = getContactListAdapter(currentGroup);
					cl.put(c);
				}
			}
		}

	}

	/**
	 * 监听滑动事件
	 */
	private class OnPageChangeListener extends
			ViewPager.SimpleOnPageChangeListener {

		/**
		 * Create a {@link OnPageChangeListener}.
		 */
		public OnPageChangeListener() {
		}

		@Override
		public void onPageSelected(int position) {
			GroupHolder.setUniquePrincipal(mListGroup, position);
			if (groupGallery != null) {
				groupGallery.setSelection(position);
			}
			mAdapterBanner.notifyDataSetChanged();
		}
	}

	/**
	 * Event simple click on middle groupe name.
	 */
	private class OnItemClickGroupName implements OnItemClickListener {

		/**
		 * Constructor.
		 */
		public OnItemClickGroupName() {
		}

		@Override
		public void onItemClick(AdapterView<?> arg0, View v, int i, long l) {
			viewPager.setCurrentItem(i, true);
		}
	}

	/**
	 * PagerAdapter for 联系人列表.
	 */
	private class ListPagerAdapter extends FragmentPagerAdapter {

		public ListPagerAdapter(final FragmentManager fm,
				final ViewPager viewPager) {
			super(fm);
			viewPager.setAdapter(this);
		}

		@Override
		public Fragment getItem(int position) {
			String group = mListGroup.get(position).groupName;
			ContactListFragment f = ContactListFragment.newInstance(group);
			f.setListAdapter(getContactListAdapter(group));
			return f;
		}

		@Override
		public int getCount() {
			return mListGroup.size();
		}

	}

	/**
	 * 
	 * to manage the state of the tabs.
	 */
	/**
	 * 一个组的持有者 代表名字和唯一 管理组的Tabs
	 * 
	 * @author LEON
	 * 
	 */
	private static class GroupHolder {
		String groupName;
		boolean isPrincipal;

		/**
		 * 
		 * 
		 * @param group
		 *            组名
		 */
		public GroupHolder(final String groupName) {
			this.groupName = groupName;
		}

		/**
		 * Create a list of GroupHolder.
		 * 
		 * @param groups
		 *            list of group name
		 * @return a list of {@link GroupHolder}
		 */
		public static List<GroupHolder> establishGroupHolder(List<String> groups) {
			List<GroupHolder> result = new ArrayList<ContactListActivity.GroupHolder>();
			for (String s : groups) {
				result.add(new GroupHolder(s));
			}
			return result;
		}

		/**
		 * 是否存在一个已知的组
		 * 
		 * @param list
		 *            所有组名
		 * @param group
		 *            需要验证的组
		 * @return true 存在 false 不存在
		 */
		public static boolean contains(List<GroupHolder> list, String group) {
			for (GroupHolder groupHolder : list) {
				if (groupHolder.groupName.equals(group))
					return true;
			}
			return false;
		}

		/**
		 * 显示当前唯一的一个ViewPager 中的组
		 * 
		 * @param groups
		 *            the list
		 * @param position
		 *            组的position
		 */
		public static void setUniquePrincipal(List<GroupHolder> groups,
				int position) {
			for (GroupHolder gh : groups) {
				gh.isPrincipal = false;
			}
			groups.get(position).isPrincipal = true;
		}
	}

}
